package com.lin.missyou.service;

import com.lin.github.wxpay.sdk.LinWxPayConfigSample;
import com.lin.github.wxpay.sdk.WXPay;
import com.lin.github.wxpay.sdk.WXPayConstants;
import com.lin.github.wxpay.sdk.WXPayUtil;
import com.lin.missyou.core.LocalUser;
import com.lin.missyou.exception.http.ForbiddenException;
import com.lin.missyou.exception.http.NotFoundException;
import com.lin.missyou.exception.http.ParameterException;
import com.lin.missyou.exception.http.ServerErrorException;
import com.lin.missyou.model.Order;
import com.lin.missyou.repository.OrderRepository;
import com.lin.missyou.util.CommonUtil;
import com.lin.missyou.util.HttpRequestProxy;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Random;

/**
 * @author gcq
 * @Create 2021-11-19
 */
@Service
public class WxPaymentService {
    @Autowired
    private OrderRepository orderRepository;
    @Autowired
    private OrderService orderService;

    @Value("${missyou.order.pay-callback-host}")
    private String payCallBackHost;

    @Value("${missyou.order.pay-callback-path}")
    private String payCallBackPath;

    /**
     * 微信配置
     */
    private static LinWxPayConfigSample linWxPayConfigSample = new LinWxPayConfigSample();

    public Map<String, String> preOrder(Long oid)
    {
        Long uid = LocalUser.getUser().getId();
        // 查询用户订单
        Optional<Order> optionalOrder = this.orderRepository.findFirstByUserIdAndId(uid, oid);
        Order order = optionalOrder.orElseThrow(() -> new NotFoundException(50009));
        if(order.needCancel())
        {
            throw new ForbiddenException(500010);
        }
        // 获取微信支付参数
        WXPay wxPay = this.assmbleWxPayConfig();
        // 准备order参数
        Map<String, String> params = this.makePreOrderParams(order.getFinalTotalPrice(), order.getOrderNo());
        Map<String, String>  wxOrder;
        try {
            wxOrder = wxPay.unifiedOrder(params);
            // 返回prepayID 微信订单的Id
        } catch (Exception e) {
            throw new ServerErrorException(9999);
        }
        // 发送请求成功 保存微信服务器返回的 支付订单Id
        if (this.unifiedOrderSuccess(wxOrder)) {
            this.orderService.updateOrderPrepayId(order.getId(), wxOrder.get("prepay_id"));
        }
        return this.makePaySignature(wxOrder);
    }

    private Map<String, String> makePaySignature(Map<String, String> wxOrder)
    {
        Map<String, String> wxPayMap = new HashMap<>();
        wxPayMap.put("appId", WxPaymentService.linWxPayConfigSample.getAppID());
        String packages = "prepay_id=" + wxOrder.get("prepay_id");
        // 时间戳
        wxPayMap.put("timeStamp", CommonUtil.timestamp10());
        // 32位随机字符串
        wxPayMap.put("nonceStr", RandomStringUtils.randomAlphabetic(32));
        // prepay_id
        wxPayMap.put("package", packages);
        // 签名算法
        wxPayMap.put("signType", "HMAC-SHA256");

        String sign;
        try {
            // 签名
            sign = WXPayUtil.generateSignature(wxPayMap, WxPaymentService.linWxPayConfigSample.getKey(), WXPayConstants.SignType.HMACSHA256);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServerErrorException(9999);
        }
        Map<String, String> miniPayParams = new HashMap<>();
        miniPayParams.put("paySign", sign);
        // 将wxPayMap 添加到 miniPayParams 中
        miniPayParams.putAll(wxPayMap);
        miniPayParams.remove("appId");
        return miniPayParams;
    }

    /**
     * 订单成功
     * @param wxOrder
     * @return
     */
    private boolean unifiedOrderSuccess(Map<String, String> wxOrder)
    {
        if(!wxOrder.get("return_code").equals("SUCCESS") || !wxOrder.get("result_code").equals("SUCCESS")){
            throw new ParameterException(10007);
        }
        return true;
    }

    /**
     * 微信请求参数
     * @param serverFinalPrice
     * @param orderNo
     * @return
     */
    private Map<String, String> makePreOrderParams(BigDecimal serverFinalPrice, String orderNo)
    {
        String payCallBackUrl = this.payCallBackHost + payCallBackPath;
        Map<String, String> map = new HashMap<>();
        map.put("body", "Sleeve");
        map.put("out_trade_no", orderNo);
        map.put("device_info", "Sleeve");
        map.put("fee_type", "CNY");
        map.put("trade_type", "JSAPI");
        // 元分转换
        map.put("total_fee", CommonUtil.yuanToFenPlainString(serverFinalPrice));
        map.put("open_id", LocalUser.getUser().getOpenid());
        // 获取用户请求的ip地址
        map.put("spbill_create_ip", HttpRequestProxy.getRemoteRealIp());

        map.put("notify_url", payCallBackUrl);

        return map;
    }

    /**
     * 准备wxPay信息
     * @return
     */
    public WXPay assmbleWxPayConfig()
    {
        WXPay wxPay = null;
        try {
            wxPay = new WXPay(WxPaymentService.linWxPayConfigSample);
        } catch (Exception e) {
            throw new ServerErrorException(9999);
        }
        return wxPay;
    }
}